﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.IO.Pipes;
using System.IO;
using System.Threading;
using System.IO.Ports;
using System.CodeDom.Compiler;
using System.IO.Pipelines;
using System.Diagnostics.CodeAnalysis;
using BootstrapBlazor.Components;
using System.Runtime.InteropServices;
using System.ComponentModel;
using static System.Net.WebRequestMethods;

namespace zy_simu.Data
{
    public delegate void EmuCommRecvCB(byte[] buf, int cnt);
    public interface IEmuComm
    {
        //public delegate void ReadCB(byte[] buf, int cnt);
        Task<bool> Open();
        Task<bool> Close();
        Task Send(byte[] buf, int cnt);
        int Recv(byte[] buf, int offset, int cnt);
    }
    public class EmuCommPipe : IEmuComm
    {
        [AllowNull] private AnonymousPipeServerStream RecvStream;
        [AllowNull] private AnonymousPipeServerStream SendStream;
        [AllowNull] private Task read_task;
        private CancellationTokenSource read_task_cancel = new CancellationTokenSource();
        private byte[] read_buf = new byte[4096];
        private int read_buf_pos = 0;

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool CreatePipe(out IntPtr hReadPipe, out IntPtr hWritePipe, ref SECURITY_ATTRIBUTES lpPipeAttributes, int nSize);
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, int nNumberOfBytesToWrite, out int lpNumberOfBytesWritten, IntPtr lpOverlapped); 
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool ReadFile(IntPtr hFile, byte[] lpBuffer, int nNumberOfBytesToRead, out int lpNumberOfBytesRead, IntPtr lpOverlapped);
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool CloseHandle(IntPtr hObject);
        [StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public int nLength;
            public IntPtr lpSecurityDescriptor;
            public int bInheritHandle;
        }

        public IntPtr RecvPortRead;
        public IntPtr RecvPortWrite;
        public IntPtr SendPortRead;
        public IntPtr SendPortWrite;
        public EmuCommPipe() 
        {
            SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
            sa.nLength = Marshal.SizeOf(sa);
            sa.bInheritHandle = 1; // 设置为可继承

            if (!CreatePipe(out RecvPortRead, out RecvPortWrite, ref sa, 4096))
            {
                throw new Win32Exception();
            }
            if (!CreatePipe(out SendPortRead, out SendPortWrite, ref sa, 4096))
            {
                throw new Win32Exception();
            }

            //RecvStream = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable, 4096);
            //SendStream = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable, 4096);
        }
        public string GetClientPort()
        {
            //string RecvPort = RecvStream.GetClientHandleAsString();
            //string SendPort = SendStream.GetClientHandleAsString();
            // 协商好, 把SendPort + "+" + RecvPort 发送给客户端， 模拟串口
            //return SendPort + "+" + RecvPort;
            return SendPortRead.ToString() + "+" + RecvPortWrite.ToString();
        }
        public string GetServerPort()
        {
            //string RecvPort = RecvStream.GetClientHandleAsString();
            //string SendPort = SendStream.GetClientHandleAsString();
            //// 协商好, RecvPort + "+" + SendPort 发送给服务器端， 模拟串口
            //return RecvPort + "+" + SendPort;
            //return SendPortWrite.ToString() + "+" + RecvPortRead.ToString();
            return RecvPortRead.ToString() + "+" + SendPortWrite.ToString();
        }
        private void data_recv()
        {
            while (!read_task_cancel.IsCancellationRequested)
            {
                byte[] buf = new byte[4096];
                int len = 0;
                try
                {
                    //len = RecvStream.Read(buf, 0, buf.Length);
                    if (!ReadFile(RecvPortRead, buf, 4096, out len, IntPtr.Zero))
                    {
                        throw new Win32Exception();
                    }
                }
                catch (Exception excp)
                {
                    System.Console.WriteLine("uart read Error: {0}", excp.Message);
                }

                if (len <= 0) continue; 
                lock (read_buf)
                {
                    if (len <= read_buf.Length - read_buf_pos)
                    {
                        Array.Copy(buf, 0, read_buf, read_buf_pos, len);
                        read_buf_pos += len;
                    }
                }
            }
        }

        // 实现IEmuComm -----------------------------------------------------------
        public async Task<bool> Open()
        {
            var cts = new CancellationTokenSource();
            //ReadThread = new System.Threading.Thread(() => data_recv());
            read_task = new Task(data_recv);
            read_task.Start();
            //ReadThread.IsBackground = true;
            //ReadThread.Start();
            // close local client
            //RecvStream.DisposeLocalCopyOfClientHandle();
            //SendStream.DisposeLocalCopyOfClientHandle();
            CloseHandle(RecvPortWrite);
            RecvPortWrite = 0;
            CloseHandle(SendPortRead);
            SendPortRead = 0;
            return true;
        }
        public async Task<bool> Close()
        {
            // TODO 通道关闭似乎导致线程退不出去
            //RecvStream.Close();
            //SendStream.Close();
            if(read_task != null)
            {
                read_task_cancel.Cancel();
                read_task = null; 
            }
            if (RecvPortRead != 0)
                CloseHandle(RecvPortRead);
            if (RecvPortWrite != 0)
                CloseHandle(RecvPortWrite);
            if(SendPortRead != 0)
                CloseHandle(SendPortRead);
            if (SendPortWrite != 0)
                CloseHandle(SendPortWrite);
            return true;
        }

        public void CloseRedundantHandleAsServer()
        {
            CloseHandle(RecvPortWrite);
            CloseHandle(SendPortRead);
        }
        public void CloseRedundantHandleAsClient()
        {
            CloseHandle(RecvPortRead);
            CloseHandle(SendPortWrite);
        }
        public async Task Send(byte[] buf, int cnt)
        {
            int bytesWritten;
            try
            {
                await Task.Run(() => {
                    if (!WriteFile(SendPortWrite, buf, cnt, out bytesWritten, IntPtr.Zero))
                    {
                        throw new Win32Exception();
                    }
                });
                //await SendStream.WriteAsync(buf, 0, cnt);
            }
            catch (Exception e)
            {
                System.Console.WriteLine("Pipe write Error: {0}", e.Message);
            }
        }

        public int Recv(byte[] buf, int offset, int cnt)
        {
            lock (read_buf)
            {
                cnt = (cnt > read_buf_pos) ? read_buf_pos : cnt;
                Array.Copy(read_buf, 0, buf, offset, cnt);
                read_buf_pos -= cnt;
                return cnt;
            }
        }

    }
}
